本文转载自以下网站:50 行代码爬取东方财富网上市公司 10 年近百万行财务报表数据 https://www.makcyun.top/web_scraping_withpython6.html
主要学习的地方:
1.分析网站的ajax请求信息
2.构造参数
3.发起请求后处理获得的数据
4.保存表格
重点:分析表格类网站的ajax请求,以及如何保存这类信息(关于表格方面的)
通过分析网址 JavaScript 请求,以比 Selenium 快 100 倍的方法,快速爬取东方财富网各上市公司历年的财务报表数据。
摘要: 上一篇文章,我们用Selenium成功爬取了东方财富网的财务报表数据,但是速度非常慢,爬取 70 页需要好几十分钟。为了加快速度,本文分析网页JavaScript请求,找到数据接口然后快速爬取财务报表数据。
1. JavaScript请求分析
接下来,我们深入分析。首先,点击报表底部的下一页,然后观察左侧Name列,看会弹出什么新的请求来:
可以看到,当不断点击下一页时,会相应弹出以get?type开头的请求。点击右边Headers选项卡,可以看到请求的URL,网址非常长,先不管它,后续我们会分析各项参数。接着,点击右侧的Preview和Response,可以看到里面有很多整齐的数据,尝试猜测这可能是财务报表中的数据,经过和表格进行对比,发现这正是我们所需的数据,太好了。
然后将URL复制到新链接中打开看看,可以看到表格中的数据完美地显示出来了。竟然不用添加Headers、UA去请求就能获取到,看来东方财富网很大方啊。
到这里,爬取思路已经很清晰了。首先,用Request请求该URL,将获取到的数据进行正则匹配,将数据转变为json格式,然后写入本地文件,最后再加一个分页循环爬取就OK了。这比之前的Selenium要简单很多,而且速度应该会快很多倍。下面我们就先来尝试爬一页数据看看。
2. 爬取单页
2.1. 抓取分析
下面,我们通过分析该url,来抓取表格内容。
import requests
def get_table():
params = {
'type': 'CWBB_LRB', # 表格类型,LRB为利润表缩写,必须
'token': '70f12f2f4f091e459a279469fe49eca5', # 访问令牌,必须
'st': 'noticedate', # 公告日期
'sr': -1, # 保持-1不用改动即可
'p': 1, # 表格页数
'ps': 50, # 每页显示多少条信息
'js': 'var LFtlXDqn={pages:(tp),data: (x)}', # js函数,必须
'filter': '(reportdate=^2018-06-30^)', # 筛选条件
# 'rt': 51294261 可不用
}
url = 'http://dcfm.eastmoney.com/em_mutisvcexpandinterface/api/js/get?'
response = requests.get(url, params=params).text
print(response)
get_table()
这里我们定义了一个get_table()方法,来输出抓取的第一页表格内容。params为url请求中所包含的参数。
这里对重要参数进行简单说明:type为7个表格的类型说明,将type拆成两部分:’CWBB_‘ 和’LRB’,资产负债表等后3个表是以’CWBB_’ 开头,业绩报表至预约披露时间表等前4个表是以’YJBB20_‘开头的;’LRB’为利润表的首字母缩写,同理业绩报表则为’YJBB’。所以,如果要爬取不同的表格,就需要更改type参数。’filter’为表格筛选参数,这里筛选出年中报的数据。不同的表格筛选条件会不一样,所以当type类型更改的时候,也要相应修改filter类型。
params参数设置好之后,将url和params参数一起传进requests.get()方法中,这样就构造好了请求连接。几行代码就可以成功获取网页第一页的表格数据了:
可以看到,表格信息存储在LFtlXDqn变量中,pages表示表格有72页。data为表格数据,是一个由多个字典构成的列表,每个字典是表格的一行数据。我们可以通过正则表达式分别提取出pages和data数据。
2.2. 正则表达式提取表格
# 确定页数
import re
pat = re.compile('var.*?{pages:(\d+),data:.*?')
page_all = re.search(pat, response)
print(page_all.group(1))
结果:
72
这里用\d+匹配页数中的数值,然后用re.search()方法提取出来。group(1)表示输出第一个结果,这里就是()中的页数。
# 提取出list,可以使用json.dumps和json.loads
import json
pattern = re.compile('var.*?data: (.*)}', re.S)
items = re.search(pattern, response)
data = items.group(1)
print(data)
print(type(data))
结果如下:
[{'scode': '600478', 'hycode': '016040', 'companycode': '10001305', 'sname'